package com.wex.posture;

import android.os.*;
import java.io.*;
import java.net.*;

/*
 基于android的socket服务器托管类
 */
public class SocketServer extends Thread
{
    /*
     服务器对外回调接口
     */
    public interface Event
    {
        //客户端接入事件
        public abstract void clientAccept(int id);
        //客户端断开事件
        public abstract void clientRemove(int id);
        //客户端发来数据
        public abstract void clientRecv(int id, byte[] data);
    }

    //线程流水号,当该值+1时,之前的线程都将关闭
    private int threadLoop = 0;
    //客户端序号,用于链表中标记和检索
    private int clientId = 1;
    //当前接入客户端链表,这里先初始化个链表头
    private FeChain<Socket> clientChain = new FeChain<>(0, null);
    //缓存参数
    private int port;
    private int blockSize;
    private Event event;
    //其它
    private Socket newClient;
    private Handler handler;

    /*
     obj: 私有数据,在回调的时候传回给使用者
     port: 服务器端口
     blockSize: 接收缓冲区大小(字节)
     event: 使用者需实现的接口
     */
    public SocketServer(int _port, int _blockSize, Event _event)
    {
        this.port = _port;
        this.blockSize = _blockSize;
        this.event = _event;
        //预置回调
        handler = new Handler() {
            @Override
            public void handleMessage(Message msg)
            {
                //不接收事件
                if (event == null)
                    return;
                switch(msg.what)
                {
                    case 0:
                        event.clientRemove(msg.arg1);
                        break;
                    case 1:
                        event.clientAccept(msg.arg1);
                        break;
                    case 2:
                        event.clientRecv(msg.arg1, (byte[])msg.obj);
                        break;
                }
            }
        };
        this.start();
    }

    @Override
    public void run()
    {
        int tLoop = threadLoop;
        try
        {
            ServerSocket serverSocket = new ServerSocket(port);
            while (tLoop == threadLoop)
            {
                newClient = null;
                //新客户端接入
                newClient = serverSocket.accept();
                if(newClient != null)
                {
                    //开线程维护连接(主要用于接收数据)
                    new Thread(new Runnable() {
                            Socket client = newClient;
                            int tLoop = threadLoop;
                            //线程体
                            public void run()
                            {
                                //客户端加入链表
                                int id = clientId++;
                                clientChain.add(id, client);
                                //事件: clientAccept
                                Message msg1 = new Message();
                                msg1.arg1 = id;
                                msg1.what = 1;
                                handler.sendMessage(msg1);
                                //轮询接收数据
                                try
                                {
                                    int length = -1;
                                    byte[] recvData = new byte[blockSize];
                                    InputStream input = client.getInputStream();
                                    /* test
                                    OutputStream output = client.getOutputStream();
                                    output.write("Hello".getBytes());
                                    output.close();*/
                                    do {
                                        if ((length = input.read(recvData)) > 0)
                                        {
                                            //事件: clientData
                                            byte[] data = new byte[length];
                                            System.arraycopy(data, 0, recvData, 0, length);
                                            Message msg2 = new Message();
                                            msg2.arg1 = id;
                                            msg2.what = 2;
                                            msg2.obj = data;
                                            handler.sendMessage(msg2);
                                        }
                                    } while (tLoop == threadLoop && client.isConnected() && length >= 0);
                                    //内存回收
                                    input.close();
                                    client.close();
                                    //事件: clientRemove
                                    Message msg0 = new Message();
                                    msg0.arg1 = id;
                                    msg0.what = 0;
                                    handler.sendMessage(msg0);

                                }
                                catch (IOException e)
                                {
                                    ;
                                }
                                //客户端移出链表
                                clientChain.remove(id);
                            }
                        }).start();
                }
            }
            //内存回收
            if (!serverSocket.isClosed())
                serverSocket.close();
        }
        catch (IOException e)
        {
            ;
        }
    }

    /*
     销毁服务器
     */
    public void exit()
    {
        threadLoop += 1;
    }

    /*
     给特定客户端发数据, 客户端已断或失效开返回false
     */
    public boolean send(int id, byte[] data)
    {
        Socket client = clientChain.find(id);
        if (client != null && !client.isClosed() && !client.isOutputShutdown())
        {
            try
            {
                OutputStream output = client.getOutputStream();
                if (output != null)
                {
                    output.write(data);
                    output.close();
                }
            }
            catch (IOException e)
            {
                clientChain.remove(id);
                return false;
            }
            return true;
        }
        return false;
    }

    /*
     给所有客户端发数据
     */
    public void broadcast(byte[] data)
    {
        try
        {
            FeChain<Socket> chain = clientChain.next;
            while (chain != null)
            {
                Socket client = chain.data;
                if (client != null && !client.isClosed() && !client.isOutputShutdown())
                {
                    OutputStream output = client.getOutputStream();
                    if (output != null)
                    {
                        output.write(data);
                        output.close();
                    }
                }
                chain = chain.next;
            }
        }
        catch (IOException e)
        {
            ;
        }
    }

}
